package com.liveinstars.im.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.liveinstars.im.common.enums.IMExceptionEnum;
import com.liveinstars.im.common.enums.PassThroughMessageTypeEnum;
import com.liveinstars.im.common.enums.SpecialUserEnum;
import com.liveinstars.im.domain.dao.model.ChatGroup;
import com.liveinstars.im.domain.dao.model.ChatGroupMember;
import com.liveinstars.im.domain.dao.model.Friends;
import com.liveinstars.im.domain.dao.model.MessageGroup;
import com.liveinstars.im.domain.manager.ChatGroupManager;
import com.liveinstars.im.domain.manager.ChatGroupMemberManager;
import com.liveinstars.im.domain.manager.FriendsManager;
import com.liveinstars.im.domain.manager.MessageGroupManager;
import com.liveinstars.im.entity.ChatMessage;
import com.liveinstars.im.entity.Msg;
import com.onepiece.cache.service.CacheService;
import com.liveinstars.im.common.exception.IMRuntimeException;
import com.liveinstars.im.core.SessionManager;
import com.liveinstars.im.core.service.MessageService;
import com.liveinstars.im.core.service.UserService;
import com.liveinstars.im.corebean.MsgHelper;
import com.onepiece.shipelves.common.utils.CacheUtil;
import com.onepiece.shipelves.common.utils.JsonUtil;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author: zhouze
 * @date: 2020/4/7
 */
@Service("messageService")
public class MessageServiceImpl implements MessageService {

    private final static Logger logger = LoggerFactory.getLogger(MessageServiceImpl.class);

    @Autowired
    private SessionManager sessionManager;

    @Autowired
    private ChatGroupMemberManager chatGroupMemberManager;

    @Autowired
    private ChatGroupManager chatGroupManager;

    @Autowired
    private MessageGroupManager messageGroupManager;
    
    @Autowired
    private FriendsManager friendsManager;

    @Autowired
    private UserService userService;

    @Autowired
    private CacheService cacheService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendMessage(ChatMessage message) {
        ChatGroup chatGroup = null;
        List<ChatGroupMember> memberList = Lists.newArrayList();
        switch (message.getMsgType()) {
            case ChatMessage.MSG_TYPE_UU:
                if( message.getToId().equals(SpecialUserEnum.IM_ASSISTANT.getId())
                        || message.getToId().equals(SpecialUserEnum.NEWS_FLASH.getId())
                        || message.getToId().equals(SpecialUserEnum.NEW_ACTIVITY.getId())) {
                } else {
                    // 查看是否是好友或者临时好友
                    if (! isFriendOrTemporary(message.getFromId(), message.getToId())) {
                        //不是则添加临时好友关系
                        userService.createTemporaryFriend(message.getFromId(), message.getToId());
                    }
                    chatGroup = chatGroupManager.getFriendsChatGroup(message.getFromId(), message.getToId());
                    if (chatGroup == null) {
                        throw new IMRuntimeException(IMExceptionEnum.FAIL_CHAT_MESSAGE);
                    }
                    memberList = chatGroupMemberManager.listMemberByChatGroupId(chatGroup.getId());
                    logger.info("点聊chatGroup {}", JSON.toJSONString(chatGroup));
                    message.setChatGroupId(chatGroup.getId());
                }
                break;
            case ChatMessage.MSG_TYPE_UCG:
                chatGroup = chatGroupManager.getById(message.getChatGroupId());
                if (chatGroup == null) {
                    throw new IMRuntimeException(IMExceptionEnum.FAIL_CHAT_GROUP_DISBAND);
                }
                memberList = chatGroupMemberManager.listMemberByChatGroupId(chatGroup.getId());
                Long fromUserId = message.getFromId();
                if (memberList.stream().noneMatch(member -> member.getUserId().equals(fromUserId))) {
                    throw new IMRuntimeException(IMExceptionEnum.FAIL_NOT_MEMBER);
                }
                logger.info("MessageServiceImpl ChatMessage.MSG_TYPE_UCG chatGrop:{} memberList:{}",JSON.toJSONString(chatGroup), JSON.toJSONString(memberList));
                break;
            default:
                break;
        }
        message = this.saveChatMessage(message, true, memberList);
        for (ChatGroupMember member : memberList) {
            message.setToId(member.getUserId());
            if (!message.getFromId().equals(member.getUserId())) {
                if (! member.getShield()) {
                    Msg.Message msg = MsgHelper.newChatMessage(message);
                    sessionManager.sendMessageRoaming(member.getUserId(), PassThroughMessageTypeEnum.USER.getValue(), msg);
                } else {
                    if (message.getMsgType().equals(ChatMessage.MSG_TYPE_UU)) {
                        throw new IMRuntimeException(IMExceptionEnum.FAIL_FRIEND_SHIELD);
                    }
                }
            }
        }
    }


    public boolean isFriendOrTemporary(Long userIdA, Long userIdB) {
        List<Friends> friendsList = friendsManager.listByUserIdAndUserFriendId(userIdA, userIdB, null);
        List<Long> userIdList = friendsList.stream().map(Friends::getFriendId).collect(Collectors.toList());
        if (userIdList.indexOf(userIdA) < 0) {
            return false;
        }
        if (userIdList.indexOf(userIdB) < 0) {
            return false;
        }
        return true;
    }

    @Override
    public ChatMessage saveChatMessage(ChatMessage message, Boolean saveCache, List<ChatGroupMember> memberList) {
        saveMessage(message);
        if(saveCache) {
            String jsonFormat = JsonUtil.toJson(message);
            logger.info("ChatHandler jsonFormat" + jsonFormat);
            if (CollectionUtils.isNotEmpty(memberList)) {
                for (ChatGroupMember member : memberList) {
                    if (!message.getFromId().equals(member.getUserId()) && !member.getShield()) {
                        cacheService.zadd(CacheUtil.getIMUserMessageList(member.getUserId()), jsonFormat, Double.valueOf(message.getId()));
                        logger.info("ChatHandler cache.zadd ucg message" + member.getUserId());
                    }
                }
            }
        }
        return message;
    }

    @Override
    public Long getMsgId() {
        String key = CacheUtil.getIMMsgID();
        int num = cacheService.incr(key);
        return (long) num;
    }


    public void saveMessage(ChatMessage message) {
        MessageGroup messageGroup = new MessageGroup();
        messageGroup.setId(message.getId());
        messageGroup.setFromId(message.getFromId());
        messageGroup.setUuid(message.getUuid());
        messageGroup.setStatus(message.getStatus());
        messageGroup.setToId(message.getToId());
        messageGroup.setContent(message.getContent());
        messageGroup.setFileName(message.getFileName());
        messageGroup.setFileType(message.getFileType());
        messageGroup.setFileParam(message.getFileParam());
        messageGroup.setPath(message.getPath());
        messageGroup.setContentType(message.getContentType());
        messageGroup.setDate(message.getDate());
        messageGroup.setType(message.getType());
        messageGroup.setMsgType(message.getMsgType());
        messageGroup.setChatGroupId(message.getChatGroupId());
        messageGroupManager.saveByGhatGroupId(messageGroup);
    }

    @Override
    public List<ChatMessage> getAllOfflineChatMessageByToId(Long toId, Long fromMessageId) {

        Set<String> zrangebyscore = cacheService.zrangebyscore(CacheUtil.getIMUserMessageList(toId), fromMessageId + 1, Long.MAX_VALUE);

        List<ChatMessage> chatMessages = new ArrayList<>();

        if(zrangebyscore != null && zrangebyscore.size() > 0) {
            for (String json : zrangebyscore) {
                chatMessages.add(JSON.parseObject(json, ChatMessage.class));
            }
        }
        return chatMessages;

    }

    /**
     * 清除所以用户离线数据
     * @param userId
     */
    @Override
    public void clearALLChatMessageByToId(Long userId) {
        cacheService.zremrangebyrank(CacheUtil.getIMUserMessageList(userId), 0L, Long.MAX_VALUE);
    }
}
